package com.yxsk.relay.job.admin.config;

import com.yxsk.relay.job.admin.core.executor.listener.JobExecuteListener;
import com.yxsk.relay.job.admin.core.executor.quartz.listener.QuartzAsyncRemoteJobExecuteListener;
import com.yxsk.relay.job.admin.core.executor.quartz.listener.QuartzRemoteJobExecuteListener;
import com.yxsk.relay.job.admin.core.schedule.RelayJobScheduleRegistrar;
import com.yxsk.relay.job.admin.core.schedule.lifecycle.manage.TaskTriggerManager;
import com.yxsk.relay.job.admin.core.schedule.quartz.QuartzDynamicScheduleService;
import com.yxsk.relay.job.admin.core.trigger.interceptor.TaskExecuteInterceptor;
import com.yxsk.relay.job.admin.core.trigger.listener.QuartzTriggerListener;
import com.yxsk.relay.job.admin.core.trigger.listener.TaskTriggerListener;
import com.yxsk.relay.job.admin.core.trigger.quartz.interceptor.QuartzExecuteBlockInterceptor;
import com.yxsk.relay.job.admin.core.trigger.quartz.interceptor.QuartzJobStatusInterceptor;
import com.yxsk.relay.job.admin.data.service.JobDetailService;
import com.yxsk.relay.job.admin.data.service.JobExecuteLogService;
import com.yxsk.relay.job.admin.data.service.JobTriggerLogService;
import com.yxsk.relay.job.component.admin.utils.SpringBeanUtils;
import com.yxsk.relay.job.component.common.exception.RelayJobRuntimeException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedList;
import java.util.List;

/**
 * @Author 11376
 * @CreaTime 2019/6/5 13:47
 * @Description
 */
@Configuration
public class TaskScheduleConfig implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        SpringBeanUtils.getBean(QuartzDynamicScheduleService.class).init();
    }

    @Bean
    public SpringBeanUtils springBeanUtils() {
        return new SpringBeanUtils();
    }

    @Bean
    public Scheduler quartzScheduler() {
        SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
        try {
            return schedulerFactoryBean.getScheduler();
        } catch (SchedulerException e) {
            throw new RelayJobRuntimeException(e);
        }
    }

    @ConditionalOnMissingBean(RelayJobScheduleRegistrar.class)
    @DependsOn("springBeanUtils")
    @Bean(destroyMethod = "destroy")
    public QuartzDynamicScheduleService quartzConfigService(@Qualifier("taskExecuteManager") TaskTriggerManager taskTriggerManager,
                                                            @Qualifier("asyncTaskExecuteManager") TaskTriggerManager asyncTaskExecuteManager) {
        return new QuartzDynamicScheduleService.QuartzDynamicScheduleConfigServiceBuilder()
                .scheduler(quartzScheduler())
                .executeManager(taskTriggerManager)
                .asyncExecuteManager(asyncTaskExecuteManager)
                .build();
    }

    @Bean
    public TaskTriggerManager taskExecuteManager(QuartzExecuteBlockInterceptor blockInterceptor,
                                                 QuartzJobStatusInterceptor statusInterceptor,
                                                 QuartzTriggerListener triggerListener,
                                                 QuartzRemoteJobExecuteListener executeListener) {
        return createTaskTriggerManager(blockInterceptor, statusInterceptor, triggerListener, executeListener);
    }

    @Bean
    public TaskTriggerManager asyncTaskExecuteManager(QuartzExecuteBlockInterceptor blockInterceptor,
                                                      QuartzJobStatusInterceptor statusInterceptor,
                                                      QuartzTriggerListener triggerListener,
                                                      QuartzAsyncRemoteJobExecuteListener asyncExecuteListener) {

        return createTaskTriggerManager(blockInterceptor, statusInterceptor, triggerListener, asyncExecuteListener);
    }

    private TaskTriggerManager createTaskTriggerManager(QuartzExecuteBlockInterceptor blockInterceptor, QuartzJobStatusInterceptor statusInterceptor, QuartzTriggerListener triggerListener, JobExecuteListener executeListener) {
        return new TaskTriggerManager() {

            @Override
            public List<TaskExecuteInterceptor> getInterceptors() {
                List<TaskExecuteInterceptor> interceptors = new LinkedList<>();
                interceptors.add(statusInterceptor);
                interceptors.add(blockInterceptor);
                return interceptors;
            }

            @Override
            public TaskTriggerListener getTriggerListener() {
                return triggerListener;
            }

            @Override
            public JobExecuteListener jobExecuteListener() {
                return executeListener;
            }

        };
    }

    @Bean
    public QuartzRemoteJobExecuteListener executeListener(JobExecuteLogService jobExecuteLogService) {
        return new QuartzRemoteJobExecuteListener(jobExecuteLogService);
    }

    @Bean
    public QuartzAsyncRemoteJobExecuteListener asyncExecuteListener(JobExecuteLogService jobExecuteLogService) {
        return new QuartzAsyncRemoteJobExecuteListener(jobExecuteLogService);
    }

    @Bean
    public QuartzTriggerListener triggerListener(JobTriggerLogService triggerLogService) {
        return new QuartzTriggerListener(triggerLogService);
    }

    @Bean
    public QuartzExecuteBlockInterceptor executeBlockInterceptor(JobExecuteLogService executeLogService) {
        return new QuartzExecuteBlockInterceptor(executeLogService);
    }

    @Bean
    public QuartzJobStatusInterceptor jobStatusInterceptor(JobDetailService detailService) {
        return new QuartzJobStatusInterceptor(detailService);
    }

}
